feature(splitter): Added support for collapsed panes state - #2299
feature(splitter): Added support for collapsed panes state#2299rkaraivanov wants to merge 9 commits into
Conversation
Added support for collapsed panes state in the splitter component. This enhancement allows developers to programmatically control the collapsed state of panes, enabling more dynamic and interactive layouts. The feature includes methods to collapse and expand panes, as well as events to listen for state changes. Closes #2297
There was a problem hiding this comment.
Pull request overview
Adds public API support for controlling and observing collapsed/expanded pane state in igc-splitter, aligning the component with the requested “persist/restore layout” scenarios.
Changes:
- Introduces
startCollapsed/endCollapsedproperties (reflected as attributes) to programmatically control pane collapsed state. - Adds
igcExpansionChangedevent and corresponding event args types/exports. - Updates Storybook stories, tests, and changelog to document and validate the new behavior.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| stories/splitter.stories.ts | Adds Storybook controls + a persisted-layout example using the new properties/event. |
| src/index.ts | Re-exports the new IgcSplitterExpansionChangedEventArgs type from the public entry. |
| src/components/splitter/types.ts | Adds the igcExpansionChanged event typing to the splitter event map. |
| src/components/splitter/splitter.ts | Implements collapsed-state properties and emits igcExpansionChanged for user interactions. |
| src/components/splitter/splitter.spec.ts | Adds unit tests for collapsed-state properties, attribute reflection, and the new event behavior. |
| CHANGELOG.md | Documents the new splitter collapsed-state API and event in the changelog. |
Comments suppressed due to low confidence (2)
src/components/splitter/splitter.ts:513
startCollapsed/endCollapsedare declared withreflect: true, but when collapsed state changes viatoggle()/_handleExpanderAction()(i.e. by updating_collapsedPane), Lit will only consider_collapsedPanechanged and will not re-reflect thestart-collapsed/end-collapsedattributes. This can leave attributes stale (e.g. switching collapsed pane from start->end can keepstart-collapsedpresent). Consider explicitly requesting updates for both public properties when_collapsedPanechanges so attribute reflection stays consistent.
this._collapsedPane = target;
this._internals.setState('start-collapsed', this._isCollapsed('start'));
this._internals.setState('end-collapsed', this._isCollapsed('end'));
src/components/splitter/splitter.ts:170
- Same as the other
@query()fields above: consider re-enabling cached queries to avoid repeated DOM lookups during interaction (consistent with other components, e.g.src/components/button/button-base.ts:54).
@query('[part~="end-pane"]')
private readonly _endPane!: HTMLElement;
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (2)
src/components/splitter/splitter.ts:163
@query('[part~="base"]')is no longer cached, which is inconsistent with other components that query a stablebasepart (e.g.src/components/tile-manager/tile.ts:189uses@query('[part~="base"]', true)). Since<div part="base">is always rendered here, caching avoids repeated DOM queries on each access and matches established pattern.
@query('[part~="base"]')
stories/splitter.stories.ts:379
- This demo reads persisted state with
JSON.parse(saved)twice and will throw if the stored value is not valid JSON (or iflocalStorageis blocked). Parsing once and guarding errors makes the story more robust.
const saved = localStorage.getItem(PERSISTED_LAYOUT_KEY);
const startCollapsed = saved ? JSON.parse(saved).startCollapsed : false;
const endCollapsed = saved ? JSON.parse(saved).endCollapsed : false;
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (3)
src/components/splitter/splitter.ts:498
- The PR description says the feature "includes methods to collapse and expand panes", but the public API changes here only add
startCollapsed/endCollapsedand reuse the existingtoggle()method (nocollapse()/expand()methods were added). Please either update the PR description or add the missing methods if they are part of the intended API.
/** Toggles the collapsed state of the specified pane. */
public toggle(position: PanePosition): void {
// If the requested pane is already collapsed, expand it (set to null)
// Otherwise, collapse the requested pane (this also handles switching from one collapsed pane to another)
this._applyCollapse(this._collapsedPane === position ? null : position);
}
stories/splitter.stories.ts:382
JSON.parse(saved)can throw iflocalStoragecontains invalid/corrupted JSON for the key, which would break the Storybook story render. Consider a small try/catch fallback to treat invalid values as "no saved layout".
const saved = localStorage.getItem(PERSISTED_LAYOUT_KEY);
const layout = saved ? JSON.parse(saved) : null;
const startSize = layout?.startSize ?? '50%';
const startCollapsed = layout?.startCollapsed ?? false;
src/components/splitter/splitter.ts:508
startCollapsed/endCollapsedare computed from_collapsedPane, but_applyCollapse()mutates_collapsedPanedirectly (viatoggle()and user interactions). Since Lit reflects attributes only for properties tracked as changed,start-collapsed/end-collapsedcan become stale when collapse state changes without going through the corresponding property setters (e.g. clicking collapse buttons or callingtoggle()). TriggerrequestUpdate()for these reactive accessor properties when_collapsedPanechanges so reflection stays in sync.
private _applyCollapse(target: PanePosition | null): void {
if (this._collapsedPane === null && target !== null) {
this._savePaneSizes();
}
…r-collapsed-panes-state
…r-collapsed-panes-state
…nged event - Removed the igcExpansionChanged event in favor of a single igcLayoutChanged event, fired after a user-driven resize (drag/keyboard) or a collapse/expand toggle, carrying a full layout snapshot (startSize, endSize, startCollapsed, endCollapsed). Simplifies persisting/restoring layout to one listener instead of two. - Fixed pane sizes collapsing to 'auto' when a pane is expanded after being collapsed programmatically before first render (e.g. restoring persisted state) - _savePaneSizes() now preserves the explicit size when layout can't be measured yet, instead of losing it. - Fixed igcLayoutChanged reporting 'auto' for the still-expanded pane's size while the other pane is collapsed - both panes' sizes are forced to 'auto' together, so both must report from the saved pre-collapse size. - Updated PersistedLayout story to use the single igcLayoutChanged listener and persist/restore startSize alongside the collapsed state. - Cleaned up JSDoc formatting on splitter properties to match repo convention (tags immediately follow description, no blank line; corrected @deprecated format on IgcSplitterResizeEventDetail).
…r-collapsed-panes-state
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
Suppressed comments (4)
src/components/splitter/splitter.ts:364
- The new boolean property JSDoc uses “Gets/sets…”. In this codebase, boolean property docs generally describe the
truestate (e.g. “When true…/Whether…”). Updating this avoids inconsistent generated docs/Storybook metadata.
/**
* Gets/sets the collapsed state of the end pane.
* @attr end-collapsed
* @default false
*/
src/components/splitter/splitter.ts:503
- The PR description mentions adding “methods to collapse and expand panes”, but the code changes introduce
startCollapsed/endCollapsed(and reusetoggle()), without newcollapse()/expand()public methods. Either update the PR description to match the implemented API, or add explicit methods if they’re part of the intended feature surface.
/** Toggles the collapsed state of the specified pane. */
public toggle(position: PanePosition): void {
// If the requested pane is already collapsed, expand it (set to null)
// Otherwise, collapse the requested pane (this also handles switching from one collapsed pane to another)
this._applyCollapse(this._collapsedPane === position ? null : position);
}
stories/splitter.stories.ts:462
JSON.parse(saved)can throw if localStorage contains invalid JSON, which would break the Storybook story rendering. Consider parsing defensively and falling back to defaults when the persisted value is corrupted.
const saved = localStorage.getItem(PERSISTED_LAYOUT_KEY);
const layout = saved ? JSON.parse(saved) : null;
src/components/splitter/splitter.ts:350
- The new boolean property JSDoc uses “Gets/sets…”. In this codebase, boolean property docs generally describe the
truestate (e.g. “When true…/Whether…”). Updating this avoids inconsistent generated docs/Storybook metadata.
This issue also appears on line 360 of the same file.
/**
* Gets/sets the collapsed state of the start pane.
* @attr start-collapsed
* @default false
*/
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
Suppressed comments (2)
src/components/splitter/splitter.ts:520
startCollapsed/endCollapsedare declared as reflected properties, but their values are derived from_collapsedPane. When_collapsedPanechanges (e.g. viatoggle()/UI interactions), Lit will re-render because_collapsedPaneis@state(), but it will not reflectstart-collapsed/end-collapsedunless those properties are marked as changed viarequestUpdate(). This can leave the reflected attributes stale after user-driven collapse/expand.
private _applyCollapse(target: PanePosition | null): void {
if (this._collapsedPane === null && target !== null) {
this._savePaneSizes();
}
this._collapsedPane = target;
this._internals.setState('start-collapsed', this._isCollapsed('start'));
this._internals.setState('end-collapsed', this._isCollapsed('end'));
this._restoreSizesOnExpandCollapse();
}
stories/splitter.stories.ts:466
JSON.parse(saved)will throw iflocalStoragecontains invalid/corrupted data for this key (which is easy to end up with during manual testing). That breaks the entire story render. Consider parsing defensively and falling back to defaults when parsing fails.
const saved = localStorage.getItem(PERSISTED_LAYOUT_KEY);
const layout = saved ? JSON.parse(saved) : null;
const startSize = layout?.startSize ?? '50%';
const startCollapsed = layout?.startCollapsed ?? false;
const endCollapsed = layout?.endCollapsed ?? false;
…r-collapsed-panes-state
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
Suppressed comments (4)
src/components/splitter/splitter.ts:367
- Same wording issue as
startCollapsed: prefer a boolean-state description (“When true…”) over “Gets/sets…”, to match existing docs and generated outputs.
/**
* Gets/sets the collapsed state of the end pane.
* @attr end-collapsed
* @default false
*/
@property({ type: Boolean, reflect: true, attribute: 'end-collapsed' })
public set endCollapsed(value: boolean) {
this._setCollapsed('end', value);
stories/splitter.stories.ts:462
JSON.parse(saved)will throw iflocalStoragecontains invalid JSON for this key, which can break the Storybook page entirely. It’s safer to parse with a try/catch and fall back tonull.
const saved = localStorage.getItem(PERSISTED_LAYOUT_KEY);
const layout = saved ? JSON.parse(saved) : null;
src/components/splitter/splitter.ts:514
startCollapsed/endCollapsedare declared withreflect: true, but collapse changes triggered viatoggle()or UI interactions only update_collapsedPane. Since Lit reflects attributes only for changed properties, thestart-collapsed/end-collapsedattributes can get out of sync (e.g. switching fromendCollapsed=truetostartCollapsed=truemay leave both attributes present). Consider explicitly requesting updates for both collapsed properties when_collapsedPanechanges so reflection stays consistent.
if (this._collapsedPane === null && target !== null) {
this._savePaneSizes();
}
this._collapsedPane = target;
src/components/splitter/splitter.ts:354
- The new boolean property docs use “Gets/sets …” wording, which is inconsistent with the rest of the component’s boolean API docs (e.g. “When true, …”). Since these descriptions flow into generated docs/Storybook, it’d be better to phrase them as a boolean state description.
This issue also appears on line 360 of the same file.
/**
* Gets/sets the collapsed state of the start pane.
* @attr start-collapsed
* @default false
*/
@property({ type: Boolean, reflect: true, attribute: 'start-collapsed' })
public set startCollapsed(value: boolean) {
this._setCollapsed('start', value);
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
Suppressed comments (4)
src/components/splitter/splitter.ts:170
_baseis queried frequently (e.g. via_getTotalSize()during resizing). Dropping the cached@query(..., true)causes repeatedquerySelectorcalls and is inconsistent with_startPane/_endPane(and other components) that cache stable part references.
@query('[part~="base"]')
private readonly _base!: HTMLElement;
stories/splitter.stories.ts:470
JSON.parse(saved)can throw iflocalStoragecontains invalid/corrupted data, which would break the Storybook story rendering. It’s safer to guard parsing and fall back to defaults.
const saved = localStorage.getItem(PERSISTED_LAYOUT_KEY);
const layout = saved ? JSON.parse(saved) : null;
src/components/splitter/splitter.ts:506
- The PR description says the feature "includes methods to collapse and expand panes", but the public API in this change exposes
startCollapsed/endCollapsedandtoggle(position)(no explicitcollapse()/expand()methods). Either add the methods or update the PR description to match the actual shipped API.
/** Toggles the collapsed state of the specified pane. */
public toggle(position: PanePosition): void {
// If the requested pane is already collapsed, expand it (set to null)
// Otherwise, collapse the requested pane (this also handles switching from one collapsed pane to another)
this._applyCollapse(this._collapsedPane === position ? null : position);
src/components/splitter/splitter.ts:517
startCollapsed/endCollapsedare reflected properties, but their values are derived from_collapsedPane. When_collapsedPanechanges via user interaction (collapse buttons, keyboard) ortoggle(), Lit will re-render due to the@state()change, but it will not automatically reflect the derived boolean attributes unless the properties are marked as changed. This can leavestart-collapsed/end-collapsedattributes stale compared to the actual collapsed state.
private _applyCollapse(target: PanePosition | null): void {
if (this._collapsedPane === null && target !== null) {
this._savePaneSizes();
}
Description
Added support for collapsed panes state in the splitter component. This enhancement allows developers to programmatically control the collapsed state of panes, enabling more dynamic and interactive layouts.
The feature includes methods to collapse and expand panes, as well as events to listen for state changes.
Type of Change
Related Issues
Closes #2297
Checklist